package view;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import model.Dimension;
import model.OnScreen;
import model.Snippet;
import model.camera.CameraManager;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;
import android.util.Log;
import android.view.SurfaceHolder;

public class SnippetRenderer implements GLSurfaceView.Renderer //, SurfaceHolder.Callback
{
	private static final String TAG = SnippetRenderer.class.getSimpleName();

    // mMVPMatrix is an abbreviation for "Model View Projection Matrix"
    private final float[] mMVPMatrix = new float[16];
    private final float[] mProjectionMatrix = new float[16];
    private final float[] mViewMatrix = new float[16];
    private final float[] mRotationMatrix = new float[16];

    private float mXAngle;
    private float mYAngle;
    
    private ArrayList<Snippet> snippets;
    private HashMap<String, Square> squares;

	@Override
	public void onSurfaceCreated(GL10 unused, EGLConfig config) 
	{
		Log.d("RENDERER", String.format("surfaceCreated()"));
        // Set the background frame color
		
    	GLES20.glClearColor(0,0,0,0);
    	
    	squares = new HashMap<String, Square>();
    	snippets = new ArrayList<Snippet>();
    	
    	for (Snippet snippet : OnScreen.getInstance().getSnippets().values()) 
    	{
    		squares.put(snippet.getId(), new Square(snippet));
		}
    }
	
	public void setSnippets(ArrayList<Snippet> snippets)
	{
		this.snippets = snippets;
	}
	
	public ArrayList<Snippet> getSnippets()
	{
		return snippets;
	}
	
	@Override
	public void onDrawFrame(GL10 unused) 
	{
//		Log.v("RENDERER", "OnDrawFrame()");
		
        float[] scratch = new float[16];

        // Draw background color
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);

        // Set the camera position (View matrix)
        Matrix.setLookAtM(mViewMatrix, 0, 0, 0, 3f, 0f, 0f, 0f, 0f, 1f, 0.0f);

        // Calculate the projection and view transformation
        Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
         
        // Combine the rotation matrix with the projection and camera view
        // Note that the mMVPMatrix factor *must be first* in order
        // for the matrix multiplication product to be correct.
        //Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, mRotationMatrix, 0);
//        mYAngle = OnScreen.getInstance().getLeftTorightCodeScale();
        
        Matrix.setRotateM(mRotationMatrix, 0, mXAngle, 1.0f, 0, 0);        
        Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, mRotationMatrix, 0);
        Matrix.setRotateM(mRotationMatrix, 0, mYAngle, 0, 1.0f, 0);
        Matrix.multiplyMM(mMVPMatrix, 0, scratch, 0, mRotationMatrix, 0);
        
		for (Snippet snippet : snippets) 
		{
			Square square = squares.get(snippet.getId());
			square.screenAreaToCoords(snippet.getScreenArea());
			square.setColor(snippet.isInformation());
			square.draw(mMVPMatrix);			
		}
        
//        new Square().draw(scratch);
    }

	@Override
	public void onSurfaceChanged(GL10 unused, int width, int height) 
	{
		Log.e("RENDERER", String.format("surfaceChanged() - {%d , %d}", width, height));
		
		OnScreen.getInstance().setScreenDimension(width, height);
		
        // Adjust the viewport based on geometry changes,
        // such as screen rotation
        GLES20.glViewport(0, 0, width, height);
        
        //stretch view to screen
        Matrix.frustumM(mProjectionMatrix, 0, -1, 1, -1, 1, 3, 7);
        
        //Set view without stretching
//        float ratio = (float) width / height;
//        Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);//        
    }

    /**
     * Utility method for compiling a OpenGL shader.
     *
     * <p><strong>Note:</strong> When developing shaders, use the checkGlError()
     * method to debug shader coding errors.</p>
     *
     * @param type - Vertex or fragment shader type.
     * @param shaderCode - String containing the shader code.
     * @return - Returns an id for the shader.
     */
    public static int loadShader(int type, String shaderCode)
    {

        // create a vertex shader type (GLES20.GL_VERTEX_SHADER)
        // or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
        int shader = GLES20.glCreateShader(type);

        // add the source code to the shader and compile it
        GLES20.glShaderSource(shader, shaderCode);
        GLES20.glCompileShader(shader);

        return shader;
    }

	/**
    * Utility method for debugging OpenGL calls. Provide the name of the call
    * just after making it:
    *
    * <pre>
    * mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
    * MyGLRenderer.checkGlError("glGetUniformLocation");</pre>
    *
    * If the operation is not successful, the check throws an error.
    *
    * @param glOperation - Name of the OpenGL call to check.
    */
    public static void checkGlError(String glOperation) 
    {
        int error;
        while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
            Log.e(TAG, glOperation + ": glError " + error);
            throw new RuntimeException(glOperation + ": glError " + error);
        }
    }

    /**
     * Returns the rotation angle of the triangle shape (mTriangle).
     *
     * @return - A float representing the rotation angle.
     */
    public float getXAngle() 
    {
        return mXAngle;
    }
    
    public float getYAngle() 
    {
        return mYAngle;
    }

    /**
     * Sets the rotation angle of the triangle shape (mTriangle).
     */
    public void setAngle(float x, float y) 
    {
        mXAngle = x;
        mYAngle = y;
    }
}